#include "socket/server.h"


namespace iecas_ns
{
    shared_ptr<CServer> CServer::sm_intancePtr = nullptr;

    CServer::CServer()
    {
        m_commonPtr = shared_ptr<CCommon>(CCommon::getInstance());
		m_jsonUsrPtr = shared_ptr<CJsonUsr>(CJsonUsr::getInstance());
		server_fd = -1;
    }

	shared_ptr<CServer> CServer::getInstance()
	{
		if(sm_intancePtr == nullptr)
		{
			sm_intancePtr = shared_ptr<CServer>(new CServer());
		}
		return sm_intancePtr;
	}

    bool CServer::init(void)
    {
		int port;
		m_jsonUsrPtr->getTcpServerPort(port);

		server_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(server_fd <= 0)
        {
            cout << "server init " << port << " faild, fd " << server_fd << endl;
            PLOGD << "server init " << port << " faild, fd " << server_fd;
            return false;
        }

		bzero(&server_sockaddr,sizeof(struct sockaddr_in));
		server_sockaddr.sin_family = AF_INET;
		server_sockaddr.sin_port = htons(port);
		server_sockaddr.sin_addr.s_addr = INADDR_ANY;

		int on=1;
		if((setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) == -1)
		{
			cout << "server init setsockopt failed" << endl;
			PLOGD << "server init setsockopt failed";
			return false;
		}

		if(bind(server_fd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1)
		{
			cout << "server init bind failed" << endl;
			PLOGD << "server init bind failed";
			return false;
		}

		if(listen(server_fd, MAX_QUE_CONN_NUM) == -1)
		{
			cout << "server init listen failed" << endl;
			PLOGD << "server init listen failed";
			return false;
		}

		cout << "server init success" << endl;
		PLOGD << "server init success";

		return true;
    }

    void CServer::start(void)
    {
        thread tempThread(&CServer::loop, this);
        tempThread.detach();
    }

    void CServer::loop(void)
    {
		int client_fd;
		string client_ip;
		struct sockaddr_in client_sockaddr;
		pid_t pid;

		while(true)
		{
			socklen_t sin_size = sizeof(struct sockaddr_in);
			if((client_fd = accept(server_fd, (struct sockaddr*)&client_sockaddr, &sin_size)) == -1)
			{
				cout << "server init accept failed" << endl;
				PLOGD << "server init accept failed";
				continue;
			}

			client_ip = inet_ntoa(client_sockaddr.sin_addr);
			cout << "server recv a connection from " << client_ip << " with fd " << client_fd << endl;
			PLOGD << "server recv a connection from " << client_ip << " with fd " << client_fd;
			m_commonPtr->addDev(client_ip, client_fd);

			thread tempThread(&CServer::do_service, this, client_ip, client_fd);
			tempThread.detach();
		}
    }

	void CServer::do_service(string client_ip, int client_fd)
	{
		int recvbytes;
		Value data;
		char buffer[MAXDATASIZE]={0};

		while(true)
		{
			if((recvbytes = recv(client_fd, buffer, MAXDATASIZE, 0)) <= 0)
			{
				break;
			}
			else
			{
				buffer[recvbytes] = '\0';
				data[SRC_DEV] = client_ip;
				data[SRC_DATA] = buffer;
				cout << "server data add dev: " << data[SRC_DEV].asString() << " data: " << data[SRC_DATA].asString() << endl;
				PLOGD << "server data add dev: " << data[SRC_DEV].asString() << " data: " << data[SRC_DATA].asString();
				m_commonPtr->addDataBack(data);
			}
		}
		cout << "server recv close" << endl;
		PLOGD << "server recv close";
		close(client_fd);
		m_commonPtr->delDev(client_ip);
	}
}
